#pragma once

#include <string>
#include <unordered_map>
#include <vector>
#include <stdexcept>
#include "viml/value.h"

namespace viml {

/**
 * 作用域标识符
 * 定义了VimL支持的所有作用域类型
 */
enum class ScopeId : uint8_t {
    GLOBAL    = 0,  // g: 全局作用域
    LOCAL     = 1,  // l: 局部作用域
    SCRIPT    = 2,  // s: 脚本作用域
    ARG       = 3,  // a: 参数作用域
    VIM       = 4,  // v: Vim内置变量
    ENV       = 5   // $ 环境变量
};

/**
 * 作用域异常
 */
class ScopeException : public std::runtime_error {
public:
    explicit ScopeException(const std::string& message)
        : std::runtime_error(message) {}
};

/**
 * 函数作用域
 * 每次函数调用时创建，包含局部变量和参数
 */
struct FunctionScope {
    std::string function_name;
    std::unordered_map<std::string, Value> local_vars;
    std::unordered_map<std::string, Value> arguments;
    size_t return_pc;  // 返回地址
    uint8_t return_reg; // 返回值寄存器
    
    FunctionScope(const std::string& name,
                 const std::vector<std::string>& param_names,
                 const std::vector<Value>& arg_values,
                 size_t ret_pc = 0,
                 uint8_t ret_reg = 0)
        : function_name(name)
        , return_pc(ret_pc)
        , return_reg(ret_reg) {
        // 初始化参数
        for (size_t i = 0; i < param_names.size() && i < arg_values.size(); ++i) {
            arguments[param_names[i]] = arg_values[i];
        }
    }
    
    bool has_local(const std::string& name) const {
        return local_vars.find(name) != local_vars.end();
    }
    
    bool has_argument(const std::string& name) const {
        return arguments.find(name) != arguments.end();
    }
    
    Value get_local(const std::string& name) const {
        auto it = local_vars.find(name);
        if (it != local_vars.end()) {
            return it->second;
        }
        throw ScopeException("Undefined local variable: " + name);
    }
    
    Value get_argument(const std::string& name) const {
        auto it = arguments.find(name);
        if (it != arguments.end()) {
            return it->second;
        }
        throw ScopeException("Undefined argument: " + name);
    }
    
    void set_local(const std::string& name, const Value& value) {
        local_vars[name] = value;
    }
};

/**
 * 作用域管理器
 * 负责管理所有作用域的变量存储和访问
 */
class ScopeManager {
private:
    // 全局作用域（单例）
    std::unordered_map<std::string, Value> global_scope_;
    
    // 脚本作用域（每个脚本文件一个）
    std::unordered_map<std::string, 
        std::unordered_map<std::string, Value>> script_scopes_;
    
    // 当前脚本名称
    std::string current_script_;
    
    // 函数作用域栈（每次函数调用创建）
    std::vector<FunctionScope> function_stack_;
    
    // Vim内置变量（只读）
    std::unordered_map<std::string, Value> vim_variables_;
    
    // 初始化Vim内置变量
    void init_vim_variables();

public:
    ScopeManager();
    
    // 作用域操作
    Value load(ScopeId scope, const std::string& name);
    void store(ScopeId scope, const std::string& name, const Value& value);
    bool exists(ScopeId scope, const std::string& name) const;
    
    // 函数作用域管理
    void push_function_scope(const std::string& func_name,
                            const std::vector<std::string>& params,
                            const std::vector<Value>& args,
                            size_t return_pc = 0,
                            uint8_t return_reg = 0);
    void pop_function_scope();
    bool in_function() const { return !function_stack_.empty(); }
    
    // 脚本作用域管理
    void enter_script(const std::string& script_name);
    void leave_script();
    const std::string& current_script() const { return current_script_; }
    
    // 重置所有作用域
    void reset();
    
    // 获取全局作用域（用于调试）
    const std::unordered_map<std::string, Value>& get_global_scope() const {
        return global_scope_;
    }
};

/**
 * 解析作用域前缀字符
 */
inline ScopeId parse_scope_prefix(char prefix) {
    switch (prefix) {
        case 'g': return ScopeId::GLOBAL;
        case 'l': return ScopeId::LOCAL;
        case 's': return ScopeId::SCRIPT;
        case 'a': return ScopeId::ARG;
        case 'v': return ScopeId::VIM;
        case '$': return ScopeId::ENV;
        default:
            throw ScopeException("Invalid scope prefix: " + std::string(1, prefix));
    }
}

/**
 * 从变量名中提取作用域和实际变量名
 * 例如：g:var -> (GLOBAL, "var")
 */
inline std::pair<ScopeId, std::string> parse_variable_name(const std::string& name) {
    if (name.length() >= 3 && name[1] == ':') {
        ScopeId scope = parse_scope_prefix(name[0]);
        std::string var_name = name.substr(2);
        return {scope, var_name};
    }
    // 默认是全局作用域
    return {ScopeId::GLOBAL, name};
}

} // namespace viml
